import numpy as np


# 测试代码
def demo(a1,a2,page,size):

    arr1 = np.array(a1)
    arr2 = np.array(a2)

    off = int((page-1)*size)
    p_off = int(off/2)
    print("总偏移量",off)
    
    # 模拟数据库select * from table limit p_off,size
    one_first = arr1[p_off:p_off+size]
    two_first = arr2[p_off:p_off+size]
    print("A库 select 结果",one_first)
    print("B库 select 结果",two_first)
    min_val = np.min(np.concatenate([one_first, two_first]))
    print("最小值",min_val)
    if len(one_first) > 0 and len(two_first) > 0:
        return all_exist(arr1, arr2, min_val, off, one_first, p_off, size, two_first)
    elif len(one_first) > 0 or len(two_first) > 0:
        return one_exist(arr1, arr2, min_val, off, size, two_first)


def one_exist(arr1, arr2, min_val, off, size, two_first):
    # select * from table where id >= min_val 选后面的size 值（原本是选取所有值，这是一种粗糙的做法，仅提供想法，细致考虑后，只取size 就足够了）,相等不应该被跳过，如果被跳过，大量连续的相等值会导致分页错误
    short_second = arr2[(arr2 >= min_val)][:size] if len(two_first) == 0 else arr1[(arr1 >= min_val)][:size]
    # 制作跳跃个数
    skip = len(arr2) - len(short_second) if len(two_first) == 0 else len(arr1) - len(short_second)
    # skip 并没有计算相等值，但是long_off 长库的偏移量可能多，因为短库可能有剩余,所以，回退短库>=相等值的数量
    long_off = off - skip - (short_second >= min_val).sum()
    # 重新查询存在的库的偏移量, 取到极端短为0 的情况，在 长库 [long_off :off - skip+size][0:size]  合并 短库 [(short_second >= min_val)][0:size]  中，一定包含了本页的值
    long_second = arr1[long_off:off - skip + size] if len(two_first) == 0 else arr2[long_off:off - skip + size]
    result = np.concatenate([short_second, long_second])
    result.sort()
    # 索引表示跳过个数，跳过 (short_second>=min_val).sum() 个，因为被容纳进来了
    queue_index = (short_second >= min_val).sum()
    print("--------------------------------------------")
    return result[queue_index:queue_index + size]


def all_exist(arr1, arr2, min_val, off, one_first, p_off, size, two_first):
    max_val = np.max([one_first[-1], two_first[-1]])
    # 知道最小值和最大值，模拟选出between
    one_second = arr1[(arr1 >= min_val) & (arr1 <= max_val)]
    two_second = arr2[(arr2 >= min_val) & (arr2 <= max_val)]
    print("A库 between 结果", one_second)
    print("B库 between 结果", two_second)
    # 选取目标队列，+1 可以排除 自身， 错误想法，必然不能排除自身，因为自身有可能就是最合适的 limit
    # 截取是以 p_off 为基准,左闭，右闭，默认为左闭右开 所以size + 1
    # 组合
    result = np.concatenate([one_second, two_second])
    # 拼接的默认无序，需要排序
    result.sort()
    # 1 列索引,如果首位相同，就说明是后扩，pOff不变，如果首位不相同，则向前推
    col_idx1 = get_col_index(one_first, one_second, p_off)
    # 2 列索引
    col_idx2 = get_col_index(two_first, two_second, p_off)
    print("两列的索引位置", col_idx1, col_idx2)
    # col_idx 可以看作另一个库的个数，直接放入另一库的偏移量，就是最小值的总偏移量
    m_off = col_idx1 + col_idx2
    print("最小值的总偏移量", m_off)
    # 计算队列内的索引位置，off - m_off 是 个数，索引 需要 - 1  ,由于 不能排除自身，所以需要+1
    queue_index = off - m_off - 1 + 1
    print("组合后的结果", result)
    print("队列内的索引", queue_index)
    print("--------------------------------------------")
    return result[queue_index:queue_index + size]


def get_col_index(first, second, p_off):
    # 记住第一次的首位，以及个数
    first_val = first[0]
    first_count = (first == first_val).sum()
    # 首位在第二次的最后位置
    pos = (second <= first_val).sum() - 1
    # 3 4  one_count = 1
    # 1 3 3 3 4  pos = 3   pos - one_count + 1 就是之前的个数
    # 从之前的off 截断, 之前的个数，几位回退的位数
    return p_off - min(len(second), pos - first_count + 1)

    

# 测试代码

def p_test():
    # min = 9    
    # moff = 3(1 索引) + 1（2索引） + 1( 2 - 1   这是 0 补) - 0(0 号位并不比9大 都是9) - 2 (相同,2个9) + 1 (由于相同全部减掉，所以补充一个，这样就能够跳到首个9)
    # moff = 4
    one = [1,4,7,9,10,11]
    two = [7,9,17,19,21,22]
    assert np.array_equal(demo(one,two,4,2) , np.array([10,11])), "测试失败"
    # min = 12 
    # moff = 6(1 索引) + 5（2索引） + 1( 2 - 1   这是 0 补) - 1(19 由于需要退位，所以，第二行也需要0补，并不是说，第二行为0，就不需要0补了) -1 (相同,只有1个12) + 1 (由于相同全部减掉，所以补充一个，这样就能够跳到首个12)
    # moff = 11
    one = [int(item) for item in "1 2 8 9 10 11 12 13 14 15 16 17 18".split(" ")]
    two = [int(item) for item in "3 4 5 6 7 19 20 22 41 42 43 44 45".split(" ")]
    assert np.array_equal(demo(one,two,4,4) , np.array([13,14,15,16])), "测试失败"
    # min = 9
    # moff = 3 + 0 + 1(2 - 1  这是 0补) - 1（13 由于需要退位，所以，第二行也需要0补，并不是说，第二行为0，就不需要0补了) - 1 (相同,只有1个9)+ 1(由于相同全部减掉，所以补充一个，这样就能够跳到首个9)
    # moff = 3
    one = [1,4,7,9,10,11]
    two = [13,15,17,19,21,22]
    assert np.array_equal(demo(one,two,4,2) , np.array([13,15])), "测试失败"

    one = [1,2,3,4,7,8,9]
    two = [1,10]
    assert np.array_equal(demo(one,two,3,2) , np.array([4,7])), "测试失败"

    one = [1,2,3,4,7,8,9]
    two = [1,2]
    assert np.array_equal(demo(one,two,3,2) , np.array([3,4])), "测试失败"

    one = [1,2,3,4,7,8,9,10]
    two = [1,5]
    assert np.array_equal(demo(one,two,5,2) , np.array([9,10])), "测试失败"

    one = [1,3,4,4,5,6]
    two = [1,5]
    assert np.array_equal(demo(one,two,3,2) , np.array([4,5])), "测试失败"

    one = [1,3,4,4,6,7]
    two = [1,5]
    assert np.array_equal(demo(one,two,3,2) , np.array([4,5])), "测试失败"

    one = [1,2,3,4,4,5,6,7,8,9]
    two = [1,5]
    assert np.array_equal(demo(one,two,6,2) , np.array([8,9])), "测试失败"

    one = [1,2,3,4,4,4,6,6,7,8,9]
    two = [1,5,5,5,5]
    assert np.array_equal(demo(one,two,6,2) , np.array([5,6])), "测试失败"

    one = [1,2,3,4,4,5,6,7,8,9,10,11]
    two = [1,1000]
    assert np.array_equal(demo(one,two,7,2) , np.array([11,1000])), "取长库的偏移+size 的界限作为最大值测试失败"

    one = [1,2,3,4,4,5,6,7,8,9,10,11,12]
    two = [1,1000]
    assert np.array_equal(demo(one,two,7,2) , np.array([11,12])), "取长库的偏移+size 的界限作为最大值测试失败"

    one = [1,2,3,4,4,4,6,6,7,8,9]
    two = []
    assert np.array_equal(demo(one,two,5,2) , np.array([7,8])), "测试失败"
p_test()